package com.wust.modules.codegenerate.generate.impl.util;

import com.wust.modules.codegenerate.util.CodeUtil;
import com.wust.modules.codegenerate.generate.prop.FileProperties;
import freemarker.template.Configuration;
import freemarker.template.Template;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import lombok.extern.slf4j.Slf4j;
import com.wust.modules.codegenerate.generate.util.FileUtil;
import com.wust.modules.codegenerate.generate.util.ConfigurationUtil;

/**
 * @author wanheng
 */
@Slf4j
public class GenerateUtil {

    protected static String UTF8 = "UTF-8";
    protected List<String> arrayList = new ArrayList();

    protected void generate(FileProperties fileProperties, String s, Map<String, Object> map) throws Exception {
        log.debug("--------generate----projectPath--------" + s);

        for (int i = 0; i < fileProperties.getFiles().size(); ++i) {
            File file = (File) fileProperties.getFiles().get(i);
            this.loadTemplate(s, file, map, fileProperties);
        }

    }

    protected void loadTemplate(String s, File file, Map<String, Object> map, FileProperties fileProperties) throws Exception {
        if (file == null) {
            throw new IllegalStateException("'templateRootDir' must be not null");
        } else {
            log.info("  load template from templateRootDir = '" + file.getAbsolutePath() + "',stylePath ='" + fileProperties.getTemplatePath() + "',  out GenerateRootDir:" + CodeUtil.filePath);
            List list = FileUtil.getFileList(file);
            log.debug("----srcFiles----size-----------" + list.size());
            log.debug("----srcFiles----list------------" + list.toString());

            for (int i = 0; i < list.size(); ++i) {
                File file1 = (File) list.get(i);
                this.outputFile(s, file, map, file1, fileProperties);
            }

        }
    }

    protected void outputFile(String s, File file, Map<String, Object> map, File file1, FileProperties fileProperties) throws Exception {
        log.debug("-------templateRootDir--" + file.getPath());
        log.debug("-------srcFile--" + file1.getPath());
        String templateFile = FileUtil.getTemplateFile(file, file1);

        try {
            log.debug("-------templateFile--" + templateFile);
            String templateFileDeal = templateFileDeal(map, templateFile, fileProperties);
            log.debug("-------outputFilepath--" + templateFileDeal);
            String s1;
            if (templateFileDeal.startsWith("java")) {
                s1 = s + File.separator + CodeUtil.sourceRootPackage.replace(".", File.separator);
                templateFileDeal = templateFileDeal.substring("java".length());
                templateFileDeal = s1 + templateFileDeal;
                log.debug("-------java----outputFilepath--" + templateFileDeal);
                this.generate(templateFile, templateFileDeal, map, fileProperties);
            } else if (templateFileDeal.startsWith("webapp")) {
                s1 = s + File.separator + CodeUtil.webRootPackage.replace(".", File.separator);
                templateFileDeal = templateFileDeal.substring("webapp".length());
                templateFileDeal = s1 + templateFileDeal;
                log.debug("-------webapp---outputFilepath---" + templateFileDeal);
                this.generate(templateFile, templateFileDeal, map, fileProperties);
            }
        } catch (Exception e) {
            log.error(e.toString(), e);
        }

    }

    protected void generate(String templateFile, String templateFileDeal, Map<String, Object> map, FileProperties fileProperties) throws Exception {
        if (templateFileDeal.endsWith("i")) {
            templateFileDeal = templateFileDeal.substring(0, templateFileDeal.length() - 1);
        }

        Template template = this.getTemplate(templateFile, fileProperties);
        template.setOutputEncoding(UTF8);
        File file = FileUtil.mkFile(templateFileDeal);
        log.info("[generate]\t template:" + templateFile + " ==> " + templateFileDeal);
        ConfigurationUtil.write(template, map, file, UTF8);
        if (!this.isStartsWith(file)) {
            this.arrayList.add("生成成功：" + templateFileDeal);
        }

        if (this.isStartsWith(file)) {
            this.generate(file, "#segment#");
        }

    }

    protected Template getTemplate(String templateFile, FileProperties fileProperties) throws IOException {
        return ConfigurationUtil.getConfiguration(fileProperties.getFiles(), UTF8, templateFile).getTemplate(templateFile);
    }

    protected boolean isStartsWith(File file) {
        return file.getName().startsWith("[1-n]");
    }

    protected void generate(File file, String s) {
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        ArrayList arrayList = new ArrayList();
        boolean b = false;

        int i;
        label341:
        {
            label342:
            {
                try {
                    b = true;
                    inputStreamReader = new InputStreamReader(new FileInputStream(file), "UTF-8");
                    bufferedReader = new BufferedReader(inputStreamReader);
                    boolean b1 = false;
                    OutputStreamWriter outputStreamWriter = null;

                    while (true) {
                        String s1;
                        while ((s1 = bufferedReader.readLine()) != null) {
                            if (s1.trim().length() > 0 && s1.startsWith(s)) {
                                String s2 = s1.substring(s.length());
                                String absolutePath = file.getParentFile().getAbsolutePath();
                                s2 = absolutePath + File.separator + s2;
                                log.info("[generate]\t split file:" + file.getAbsolutePath() + " ==> " + s2);
                                outputStreamWriter = new OutputStreamWriter(new FileOutputStream(s2), "UTF-8");
                                arrayList.add(outputStreamWriter);
                                this.arrayList.add("生成成功：" + s2);
                                b1 = true;
                            } else if (b1) {
                                outputStreamWriter.append(s1 + "\r\n");
                            }
                        }

                        for (int j = 0; j < arrayList.size(); ++j) {
                            ((Writer) arrayList.get(j)).close();
                        }

                        bufferedReader.close();
                        inputStreamReader.close();
                        log.debug("[generate]\t delete file:" + file.getAbsolutePath());
                        deleteFile(file);
                        b = false;
                        break label341;
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                    b = false;
                    break label342;
                } catch (IOException e) {
                    e.printStackTrace();
                    b = false;
                } finally {
                    if (b) {
                        try {
                            if (bufferedReader != null) {
                                bufferedReader.close();
                            }

                            if (inputStreamReader != null) {
                                inputStreamReader.close();
                            }

                            if (arrayList.size() > 0) {
                                for (int k = 0; k < arrayList.size(); ++k) {
                                    if (arrayList.get(k) != null) {
                                        ((Writer) arrayList.get(k)).close();
                                    }
                                }
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                    }
                }

                try {
                    if (bufferedReader != null) {
                        bufferedReader.close();
                    }

                    if (inputStreamReader != null) {
                        inputStreamReader.close();
                    }

                    if (arrayList.size() > 0) {
                        for (i = 0; i < arrayList.size(); ++i) {
                            if (arrayList.get(i) != null) {
                                ((Writer) arrayList.get(i)).close();
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }

                return;
            }

            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }

                if (inputStreamReader != null) {
                    inputStreamReader.close();
                }

                if (arrayList.size() > 0) {
                    for (i = 0; i < arrayList.size(); ++i) {
                        if (arrayList.get(i) != null) {
                            ((Writer) arrayList.get(i)).close();
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            return;
        }

        try {
            if (bufferedReader != null) {
                bufferedReader.close();
            }

            if (inputStreamReader != null) {
                inputStreamReader.close();
            }

            if (arrayList.size() > 0) {
                for (i = 0; i < arrayList.size(); ++i) {
                    if (arrayList.get(i) != null) {
                        ((Writer) arrayList.get(i)).close();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    protected static String templateFileDeal(Map<String, Object> map, String templateFile, FileProperties fileProperties) throws Exception {
        String templateFile1 = templateFile;
        int i;
        if ((i = templateFile.indexOf(64)) != -1) {
            templateFile1 = templateFile.substring(0, i);
            String substring = templateFile.substring(i + 1);
            Object object = map.get(substring);
            if (object == null) {
                System.err.println("[not-generate] WARN: test expression is null by key:[" + substring + "] on template:[" + templateFile + "]");
                return null;
            }

            if (!"true".equals(String.valueOf(object))) {
                log.error("[not-generate]\t test expression '@" + substring + "' is false,template:" + templateFile);
                return null;
            }
        }

        Configuration configuration = ConfigurationUtil.getConfiguration(fileProperties.getFiles(), UTF8, "/");
        templateFile1 = ConfigurationUtil.getStringWriter(templateFile1, map, configuration);
        String templatePath = fileProperties.getTemplatePath();
        if (templatePath != null && templatePath != "") {
            templateFile1 = templateFile1.substring(templatePath.length() + 1);
        }

        String substring = templateFile1.substring(templateFile1.lastIndexOf("."));
        String substring1 = templateFile1.substring(0, templateFile1.lastIndexOf(".")).replace(".", File.separator);
        templateFile1 = substring1 + substring;
        return templateFile1;
    }

    protected static void deleteFile(File file) {
        boolean b = false;

        for (int i = 0; !b && i++ < 10; b = file.delete()) {
            System.gc();
        }

    }

    protected static String substring(String s, String s1) {
        boolean b = true;
        boolean b1 = true;

        do {
            int i = s.indexOf(s1) == 0 ? 1 : 0;
            int j = s.lastIndexOf(s1) + 1 == s.length() ? s.lastIndexOf(s1) : s.length();
            s = s.substring(i, j);
            b = s.indexOf(s1) == 0;
            b1 = s.lastIndexOf(s1) + 1 == s.length();
        } while (b || b1);

        return s;
    }
}
